<template>
  <view class="bottle-container" :class="theme">
    <view class="theme-switch">
      <button v-for="(themeName, key) in themeColors" :key="key" @click="switchTheme(key)" :class="{ active: theme === key }" :style="{ backgroundColor: themeName.main, color: '#fff' }">
        {{ themeName.name }}
      </button>
    </view>
    <view class="svg-bottle-wrapper" @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd">
      <svg class="bottle-svg" viewBox="-76 0 292 292" xmlns="http://www.w3.org/2000/svg">
        <defs>
          <!-- 粉色渐变 -->
          <linearGradient :id="'bottleGradient-' + theme" x1="0%" y1="0%" x2="0%" y2="100%">
            <stop offset="0%" :stop-color="themeColors[theme].bottleTop" />
            <stop offset="100%" :stop-color="themeColors[theme].bottleBottom" />
          </linearGradient>
          <linearGradient :id="'milkGradient-' + theme" x1="0%" y1="0%" x2="0%" y2="100%">
            <stop offset="0%" :stop-color="themeColors[theme].milkTop" />
            <stop offset="100%" :stop-color="themeColors[theme].milkBottom" />
          </linearGradient>
          <radialGradient :id="'highlightGradient-' + theme" cx="50%" cy="20%" r="80%">
            <stop offset="0%" stop-color="#fff" stop-opacity="0.7" />
            <stop offset="100%" stop-color="#fff" stop-opacity="0" />
          </radialGradient>
          <clipPath id="bottleClip">
            <path d="M16.257,281.456a28.754,28.754,0,0,1-12.648-17.82c-1.788-7.126-1.109-17.568-.5-31.019.835-18.431,3.947-79.695,4.527-93.677A43.578,43.578,0,0,1,10.9,124.505a25.89,25.89,0,0,1,5.664-8.6l.032-.028a28.34,28.34,0,0,0,7.61,2.365,272.855,272.855,0,0,0,45.4,3.4,272.233,272.233,0,0,0,45.749-3.459,23.016,23.016,0,0,0,8.171-2.3.3.3,0,0,1,.032.024,25.89,25.89,0,0,1,5.664,8.6,43.554,43.554,0,0,1,3.265,14.435c.58,13.982,3.692,75.246,4.527,93.677.609,13.451,1.288,23.893-.5,31.019-2.606,10.391-9.1,16.89-19.125,21.292-13.28,3.817-28.787,4.779-47.783,4.779-18.249,0-34.711-.962-46.224-4.5A44.77,44.77,0,0,1,16.257,281.456Z" />
          </clipPath>
        </defs>
        <!-- 奶液层（底部对齐，动态高度，顶部为水波线，clip-path裁剪） -->
        <path :d="milkWavePath" :fill="'url(#milkGradient-' + theme + ') '" clip-path="url(#bottleClip)" :style="animOn ? 'transition: d 0.5s cubic-bezier(.4,1.6,.4,1);' : ''" />
        <!-- 奶液波浪高光（已去除左上角高光，仅保留奶液表面高光） -->
        <path :d="milkWaveHighlightPath" :fill="'url(#highlightGradient-' + theme + ') '" clip-path="url(#bottleClip)" :style="'pointer-events:none;'" />
        <!-- 只画瓶身描边，不画填充 -->
        <path class="a" d="M45.074,46.263a103.671,103.671,0,0,0-9.862,5.923c-8.244,5.894-14.28,14.585-9.875,27.821A274.584,274.584,0,0,0,69.6,83.226a275.573,275.573,0,0,0,44.268-3.212c4.4-13.241-1.632-21.933-9.877-27.828C95.482,46.1,84.69,42.911,83.987,36.72L83.946,18c-.008-3.7-.914-8.174-3.262-11.034C78.587,4.417,74.1,2.359,69.6,2.359S60.617,4.417,58.52,6.97C56.172,9.83,55.266,14.3,55.258,18L55.217,36.72C54.777,40.6,50.385,43.294,45.074,46.263Z" fill="none" :stroke="themeColors[theme].bottleStroke" stroke-width="4" />
        <path class="a" d="M16.257,281.456a28.754,28.754,0,0,1-12.648-17.82c-1.788-7.126-1.109-17.568-.5-31.019.835-18.431,3.947-79.695,4.527-93.677A43.578,43.578,0,0,1,10.9,124.505a25.89,25.89,0,0,1,5.664-8.6l.032-.028a28.34,28.34,0,0,0,7.61,2.365,272.855,272.855,0,0,0,45.4,3.4,272.233,272.233,0,0,0,45.749-3.459,23.016,23.016,0,0,0,8.171-2.3.3.3,0,0,1,.032.024,25.89,25.89,0,0,1,5.664,8.6,43.554,43.554,0,0,1,3.265,14.435c.58,13.982,3.692,75.246,4.527,93.677.609,13.451,1.288,23.893-.5,31.019-2.606,10.391-9.1,16.89-19.125,21.292-13.28,3.817-28.787,4.779-47.783,4.779-18.249,0-34.711-.962-46.224-4.5A44.77,44.77,0,0,1,16.257,281.456Z" fill="none" :stroke="themeColors[theme].bottleStroke" stroke-width="4" />
        <!-- <path class="b" d="M137.01,232.617c-.429-9.474-1.46-30.262-2.439-50.13-17.994,3-39.178,4.776-64.511,4.776s-46.518-1.779-64.512-4.776c-.979,19.868-2.01,40.656-2.439,50.13-.609,13.451-1.288,23.893.5,31.019,2.662,10.612,9.382,17.166,19.769,21.575q1.383.425,2.858.8c11.3,2.882,26.578,3.7,43.366,3.7,19,0,34.5-.962,47.783-4.779,10.022-4.4,16.519-10.9,19.125-21.292C138.3,256.51,137.619,246.068,137.01,232.617Z" fill="none" :stroke="themeColors[theme].bottleStroke" stroke-width="3" /> -->
        <path class="c" d="M116.056,79.793q-.384-.021-.77-.015A272.409,272.409,0,0,1,69.6,83.226,270.53,270.53,0,0,1,24.07,79.785a11.85,11.85,0,0,0-8.707,4.6c-2.536,3.371-3.292,7.722-3.835,11.9a69.32,69.32,0,0,0-.829,10.972c-.053,2.419,2.538,6.516,4.089,7.556,2.709,1.817,5.437,2.631,9.418,3.429a272.868,272.868,0,0,0,45.4,3.4,272.233,272.233,0,0,0,45.749-3.459,21.633,21.633,0,0,0,9.981-3.371c1.55-1.04,4.141-5.137,4.088-7.556a69.32,69.32,0,0,0-.829-10.972c-.543-4.182-1.3-8.533-3.835-11.9A11.817,11.817,0,0,0,116.056,79.793Z" fill="none" :stroke="themeColors[theme].bottleStroke" stroke-width="2.5" />
        <!-- 刻度线放到瓶身内侧，只在瓶身范围内显示 -->
        <g>
          <line v-for="mark in scaleMarks" :key="mark" :x1="115" :y1="getScaleY(mark)" :x2="125" :y2="getScaleY(mark)" :stroke="themeColors[theme].scale" stroke-width="2" opacity="0.8" />
          <text v-for="mark in scaleMarks" :key="'text-' + mark" :x="130" :y="getScaleY(mark) + 4" :fill="themeColors[theme].scale" font-size="11" font-family="Arial" opacity="0.9">{{ mark }}</text>
        </g>
        <!-- 高光 -->
        <!-- <ellipse cx="30" cy="120" rx="8" ry="80" :fill="'url(#highlightGradient-' + theme + ') '" opacity="0.7" /> -->
        <!-- 投影 -->
        <ellipse cx="70" cy="290" rx="60" ry="10" :fill="themeColors[theme].shadow" opacity="0.18" />
      </svg>
      <!-- 奶量数字移到奶瓶下方 -->
      <view class="milk-amount-below" :class="{ bounce: animOn && amountBounce }">
        <text class="milk-amount-main">{{ selectedAmount }}</text>
        <text class="milk-amount-unit">ml</text>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  name: 'BottleDemoSVG',
  data() {
    return {
      selectedAmount: 100,
      maxAmount: 240,
      minAmount: 10,
      touchStartY: 0,
      touchStartAmount: 100,
      theme: 'dark',
      animOn: true,
      amountBounce: false,
      waveTimer: null,
      isSliding: false, // 是否正在滑动
      slideEndTimer: null, // 滑动结束定时器
      waveIntensity: 0, // 波纹强度 0-1，0为平滑，1为最大波纹
      waveDecayTimer: null, // 波纹衰减定时器
      themeColors: {
        pink: {
          name: '粉色',
          main: '#ff69b4',
          bottleTop: '#fff0f5',
          bottleBottom: '#ffb6c1',
          bottleStroke: '#ffb6c1',
          milkTop: '#fff0f5',
          milkBottom: '#ffb6c1',
          scale: '#ffb6c1',
          shadow: '#ffb6c1'
        },
        blue: {
          name: '蓝色',
          main: '#4285f4',
          bottleTop: '#e3f2fd',
          bottleBottom: '#90caf9',
          bottleStroke: '#90caf9',
          milkTop: '#e3f2fd',
          milkBottom: '#90caf9',
          scale: '#90caf9',
          shadow: '#90caf9'
        },
        green: {
          name: '绿色',
          main: '#34a853',
          bottleTop: '#e8f5e8',
          bottleBottom: '#81c784',
          bottleStroke: '#81c784',
          milkTop: '#e8f5e8',
          milkBottom: '#81c784',
          scale: '#81c784',
          shadow: '#81c784'
        },
        purple: {
          name: '紫色',
          main: '#9c27b0',
          bottleTop: '#f3e5f5',
          bottleBottom: '#ce93d8',
          bottleStroke: '#ce93d8',
          milkTop: '#f3e5f5',
          milkBottom: '#ce93d8',
          scale: '#ce93d8',
          shadow: '#ce93d8'
        },
        orange: {
          name: '橙色',
          main: '#ff9800',
          bottleTop: '#fff8e1',
          bottleBottom: '#ffcc02',
          bottleStroke: '#ffcc02',
          milkTop: '#fff8e1',
          milkBottom: '#ffcc02',
          scale: '#ffcc02',
          shadow: '#ffcc02'
        },
        dark: {
          name: '深色',
          main: '#333',
          bottleTop: '#444',
          bottleBottom: '#222',
          bottleStroke: '#fff',
          milkTop: '#fff',
          milkBottom: '#bbb',
          scale: '#fff',
          shadow: '#000'
        }
      },
      scaleMarks: [50, 100, 150, 200, 240]
    }
  },
  computed: {
    milkHeight() {
      const percent =
        (this.selectedAmount - this.minAmount) /
        (this.maxAmount - this.minAmount)
      return Math.max(percent * 220, 8)
    },
    milkWavePath() {
      // 奶液表面波纹滚动效果 - 支持渐变过渡
      const y = 292 - this.milkHeight

      // 当波纹强度很低时，混合轻微波动和衰减波纹
      if (this.waveIntensity <= 0.1) {
        // 计算轻微波动
        const gentleAmp = 0.8 // 非常轻微的波浪幅度
        const gentleFreq = 1.5 // 较低的频率
        const step = 20 // 较大的步长，让波浪更平滑
        let d = `M-76,${y}`
        for (let x = -76; x <= 216; x += step) {
          const time = Date.now() / 8000 // 非常慢的滚动速度
          const gentleWaveY =
            y + Math.sin((x / 60 + time) * Math.PI * gentleFreq) * gentleAmp

          // 如果还有衰减波纹，则混合两种效果
          let finalWaveY = gentleWaveY
          if (this.waveIntensity > 0.01) {
            const decayTime = Date.now() / 2000
            const decayWaveY =
              y +
              Math.sin((x / 20 + decayTime) * Math.PI * 3) *
                (3 * this.waveIntensity)
            // 平滑混合：衰减波纹逐渐减弱，轻微波动逐渐增强
            const mixRatio = this.waveIntensity / 0.1 // 0.01-0.1 映射到 0.1-1
            finalWaveY = gentleWaveY * (1 - mixRatio) + decayWaveY * mixRatio
          }

          d += ` Q${x + step / 2},${finalWaveY - gentleAmp / 3} ${
            x + step
          },${finalWaveY}`
        }
        d += ` V292 H-76 Z`
        return d
      }

      // 根据波纹强度调整波纹参数
      const baseAmp = 3 // 基础波纹幅度
      const amp = baseAmp * this.waveIntensity, // 根据强度调整幅度
        freq = 3, // 增加波纹频率
        len = 292,
        step = 12 // 减小步长，让波纹更平滑
      let d = `M-76,${y}`
      for (let x = -76; x <= 216; x += step) {
        const time = Date.now() / 2000 // 加快滚动速度
        const waveY = y + Math.sin((x / 20 + time) * Math.PI * freq) * amp
        d += ` Q${x + step / 2},${waveY - amp / 2} ${x + step},${waveY}`
      }
      d += ` V292 H-76 Z`
      return d
    },
    milkWaveHighlightPath() {
      // 高光波浪，与主波纹略有不同的频率产生层次感 - 支持渐变过渡
      const y = 292 - this.milkHeight - 2

      // 当波纹强度很低时，混合轻微波动和衰减波纹
      if (this.waveIntensity <= 0.1) {
        // 计算轻微高光波动
        const gentleAmp = 0.5 // 更轻微的高光波浪幅度
        const gentleFreq = 1.2 // 稍微不同的频率
        const step = 20 // 较大的步长，让波浪更平滑
        let d = `M-76,${y}`
        for (let x = -76; x <= 216; x += step) {
          const time = Date.now() / 9000 // 稍微不同的速度
          const gentleWaveY =
            y +
            Math.sin((x / 70 + time + 0.3) * Math.PI * gentleFreq) * gentleAmp

          // 如果还有衰减波纹，则混合两种效果
          let finalWaveY = gentleWaveY
          if (this.waveIntensity > 0.01) {
            const decayTime = Date.now() / 2500
            const decayWaveY =
              y +
              Math.sin((x / 25 + decayTime + 0.5) * Math.PI * 2.5) *
                (2 * this.waveIntensity)
            // 平滑混合：衰减波纹逐渐减弱，轻微波动逐渐增强
            const mixRatio = this.waveIntensity / 0.1 // 0.01-0.1 映射到 0.1-1
            finalWaveY = gentleWaveY * (1 - mixRatio) + decayWaveY * mixRatio
          }

          d += ` Q${x + step / 2},${finalWaveY - gentleAmp / 3} ${
            x + step
          },${finalWaveY}`
        }
        d += ` V292 H-76 Z`
        return d
      }

      // 根据波纹强度调整高光波纹参数
      const baseAmp = 2 // 基础高光波纹幅度
      const amp = baseAmp * this.waveIntensity,
        freq = 2.5,
        len = 292,
        step = 12
      let d = `M-76,${y}`
      for (let x = -76; x <= 216; x += step) {
        const time = Date.now() / 2500 // 稍微不同的速度
        const waveY = y + Math.sin((x / 25 + time + 0.5) * Math.PI * freq) * amp
        d += ` Q${x + step / 2},${waveY - amp / 2} ${x + step},${waveY}`
      }
      d += ` V292 H-76 Z`
      return d
    }
  },
  watch: {
    selectedAmount() {
      if (this.animOn) {
        this.amountBounce = false
        this.$nextTick(() => {
          this.amountBounce = true
        })
      }
    }
  },
  mounted() {
    // 启动波纹滚动动画
    this.startWaveAnimation()
  },
  beforeDestroy() {
    // 清理动画定时器
    if (this.waveTimer) {
      clearInterval(this.waveTimer)
    }
    // 清理滑动结束定时器
    if (this.slideEndTimer) {
      clearTimeout(this.slideEndTimer)
    }
    // 清理波纹衰减定时器
    if (this.waveDecayTimer) {
      clearInterval(this.waveDecayTimer)
    }
  },
  onShow() {
    // 进入奶瓶页面时禁用滚动
    document.body.style.overflow = 'hidden'
    // 重新启动波纹动画
    this.startWaveAnimation()
  },
 
  methods: {
    getScaleY(mark) {
      // 刻度线Y坐标，只在瓶身下半部分（Y坐标约150-270，再往下移动）
      const percent =
        (mark - this.minAmount) / (this.maxAmount - this.minAmount)
      const bottleBodyStart = 150 // 瓶身开始位置（更往下移）
      const bottleBodyEnd = 270 // 瓶身结束位置（瓶底上方）
      const bottleBodyHeight = bottleBodyEnd - bottleBodyStart
      return bottleBodyEnd - Math.max(percent * bottleBodyHeight, 8)
    },
    switchTheme(themeName) {
      this.theme = themeName
    },
    startWaveAnimation() {
      // 清理之前的定时器
      if (this.waveTimer) {
        clearInterval(this.waveTimer)
      }
      // 启动新的波纹动画定时器，每16ms更新一次（约60fps）
      this.waveTimer = setInterval(() => {
        this.$forceUpdate() // 强制更新，重新计算波纹路径
      }, 16)
    },
    onTouchStart(e) {
      this.touchStartY = e.touches[0].clientY
      this.touchStartAmount = this.selectedAmount

      // 开始滑动，启用波纹动画
      this.isSliding = true
      this.waveIntensity = 1 // 立即设置为最大波纹强度

      // 清理之前的定时器
      if (this.slideEndTimer) {
        clearTimeout(this.slideEndTimer)
      }
      if (this.waveDecayTimer) {
        clearInterval(this.waveDecayTimer)
      }
    },
    onTouchMove(e) {
      const deltaY = this.touchStartY - e.touches[0].clientY
      const deltaAmount = Math.round(deltaY * 0.5)
      let newAmount = this.touchStartAmount + deltaAmount
      newAmount = Math.max(this.minAmount, Math.min(this.maxAmount, newAmount))
      newAmount = Math.round(newAmount / 5) * 5
      this.selectedAmount = newAmount
    },
    onTouchEnd() {
      // 滑动结束后，开始波纹衰减动画
      this.isSliding = false
      this.startWaveDecay()
    },
    startWaveDecay() {
      // 清理之前的衰减定时器
      if (this.waveDecayTimer) {
        clearInterval(this.waveDecayTimer)
      }

      // 开始波纹衰减动画
      this.waveDecayTimer = setInterval(() => {
        if (this.waveIntensity > 0) {
          this.waveIntensity -= 0.008 // 每次减少0.008，大约125帧后完全平滑（约2秒）
          if (this.waveIntensity < 0) {
            this.waveIntensity = 0
          }
        } else {
          // 波纹完全消失，清理定时器
          clearInterval(this.waveDecayTimer)
          this.waveDecayTimer = null
        }
      }, 16) // 每16ms更新一次，约60fps
    }
  }
}
</script>

<style scoped>
.bottle-container {
  min-height: 100vh;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background: #fff;
  position: relative;
  transition: background 0.3s;
  overflow: hidden;
}
.bottle-container.blue {
  background: linear-gradient(135deg, #e3f2fd, #f0f8ff);
}
.bottle-container.green {
  background: linear-gradient(135deg, #e8f5e8, #f1f8e9);
}
.bottle-container.purple {
  background: linear-gradient(135deg, #f3e5f5, #fce4ec);
}
.bottle-container.orange {
  background: linear-gradient(135deg, #fff8e1, #fefbf3);
}
.bottle-container.dark {
  background: #181828;
}
.theme-switch {
  position: absolute;
  top: 18px;
  right: 18px;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  max-width: 200px;
}
.theme-switch button {
  border: none;
  border-radius: 20px;
  padding: 8px 12px;
  font-size: 14px;
  font-weight: bold;
  cursor: pointer;
  transition: all 0.3s ease;
  opacity: 0.8;
  transform: scale(0.9);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.theme-switch button.active {
  opacity: 1;
  transform: scale(1);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
}
.svg-bottle-wrapper {
  position: relative;
  width: 320px;
  height: 320px;
  display: flex;
  justify-content: center;
  align-items: center;
  filter: drop-shadow(0 8px 32px #ffb6c133);
}
.bottle-container.dark .svg-bottle-wrapper {
  filter: drop-shadow(0 8px 32px #0006);
}
.bottle-svg {
  width: 100%;
  height: 100%;
  display: block;
}
.milk-amount {
  display: none;
}
.milk-amount-below {
  position: absolute;
  left: 50%;
  top: 100%;
  transform: translate(-50%, 20px);
  display: flex;
  align-items: flex-end;
  background: rgba(255, 255, 255, 0.7);
  border-radius: 20px;
  padding: 8px 18px;
  box-shadow: 0 2px 12px #ffb6c133;
  transition: box-shadow 0.2s, background 0.2s;
  z-index: 2;
}
.bottle-container.dark .milk-amount-below {
  background: rgba(40, 40, 40, 0.7);
  box-shadow: 0 2px 12px #0006;
}
.milk-amount-main {
  font-size: 40px;
  font-weight: bold;
  margin-right: 6px;
  transition: color 0.2s;
}
.bottle-container.pink .milk-amount-main {
  color: #ff69b4;
  text-shadow: 0 2px 8px #fff0f5;
}
.bottle-container.blue .milk-amount-main {
  color: #4285f4;
  text-shadow: 0 2px 8px #e3f2fd;
}
.bottle-container.green .milk-amount-main {
  color: #34a853;
  text-shadow: 0 2px 8px #e8f5e8;
}
.bottle-container.purple .milk-amount-main {
  color: #9c27b0;
  text-shadow: 0 2px 8px #f3e5f5;
}
.bottle-container.orange .milk-amount-main {
  color: #ff9800;
  text-shadow: 0 2px 8px #fff8e1;
}
.bottle-container.dark .milk-amount-main {
  color: #fff;
  text-shadow: 0 2px 8px #000;
}
.milk-amount-unit {
  font-size: 20px;
  font-weight: 500;
  transition: color 0.2s;
}
.bottle-container.pink .milk-amount-unit {
  color: #ffb6c1;
}
.bottle-container.blue .milk-amount-unit {
  color: #90caf9;
}
.bottle-container.green .milk-amount-unit {
  color: #81c784;
}
.bottle-container.purple .milk-amount-unit {
  color: #ce93d8;
}
.bottle-container.orange .milk-amount-unit {
  color: #ffcc02;
}
.bottle-container.dark .milk-amount-unit {
  color: #fff;
}
.milk-amount.bounce {
  animation: bounce 0.4s cubic-bezier(0.4, 1.6, 0.4, 1);
}
@keyframes bounce {
  0% {
    transform: translate(-50%, -50%) scale(1);
  }
  40% {
    transform: translate(-50%, -60%) scale(1.18);
  }
  100% {
    transform: translate(-50%, -50%) scale(1);
  }
}
.svg-bottle-wrapper:active {
  transform: scale(0.98);
  transition: transform 0.1s ease;
}
@media (max-width: 600px) {
  .svg-bottle-wrapper {
    width: 90vw;
    height: 90vw;
    max-width: 400px;
    max-height: 400px;
  }
}
</style>

 